package com.ccrfid.rmc6.service.mattress;

import com.google.common.eventbus.EventBus;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
@ConditionalOnProperty(name = "ht.mattress.service.enabled", havingValue = "true", matchIfMissing = false)
public class MattressDataReceiver {
    private static final Logger logger = LoggerFactory.getLogger(MattressDataReceiver.class);

    @Autowired
    private EventBus eventBus;
    @Value("${ht.mattress.service.port}")
    private Integer servicePort;

    @PostConstruct
    private void startup() {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                EventLoopGroup bossGroup = new NioEventLoopGroup(1);
                EventLoopGroup workerGroup = new NioEventLoopGroup();
                try {
                    ServerBootstrap b = new ServerBootstrap();
                    b.group(bossGroup, workerGroup)
                            .channel(NioServerSocketChannel.class)
                            .handler(new LoggingHandler(LogLevel.INFO))
                            .childHandler(new ChannelInitializer<SocketChannel>() {
                                @Override
                                public void initChannel(SocketChannel ch) throws Exception {
                                    ByteBuf delimiter = Unpooled.copiedBuffer(new byte[]{(byte) 0xab, (byte) 0xcd});
                                    ChannelPipeline p = ch.pipeline();
                                    p.addLast(new IdleStateHandler(0, 0, 300))
                                            .addLast(new DelimiterBasedFrameDecoder(8192, true, delimiter))
                                            .addLast(new MattressDataHandler(eventBus));
                                }
                            });
                    // Bind and start to accept incoming connections.
                    b.bind(servicePort).sync().channel().closeFuture().sync();
                } catch (InterruptedException ex) {
                    logger.error("** mattress.service startup() failed!!!");
                    ex.printStackTrace();
                } finally {
                    bossGroup.shutdownGracefully();
                    workerGroup.shutdownGracefully();
                }
            }
        });
        thread.start();
        logger.debug("** mattress.service startup() ...");
    }
}
